package tools

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"workflow-gui/internal/ai"
	"workflow-gui/internal/database"
	"workflow-gui/internal/protocol"
	"workflow-gui/internal/workflow"
)

// TaskExecutionHandler handles task execution requests
type TaskExecutionHandler struct {
	db           *database.DB
	aiClient     *ai.AIClient
	promptEngine *ai.PromptEngine
}

// NewTaskExecutionHandler creates a new task execution handler
func NewTaskExecutionHandler(db *database.DB, aiClient *ai.AIClient, promptEngine *ai.PromptEngine) *TaskExecutionHandler {
	return &TaskExecutionHandler{
		db:           db,
		aiClient:     aiClient,
		promptEngine: promptEngine,
	}
}

// TaskExecutionResponse represents the task execution response
type TaskExecutionResponse struct {
	Code     string `json:"code"`
	FilePath string `json:"file_path"`
	Summary  string `json:"summary"`
}

// HandleExecuteTask handles task execution request
func (h *TaskExecutionHandler) HandleExecuteTask(args map[string]interface{}) (protocol.ToolResult, error) {
	// Extract task_id
	taskIDFloat, ok := args["task_id"].(float64)
	if !ok {
		return protocol.NewErrorResult("Missing or invalid argument: task_id"), nil
	}
	taskID := int(taskIDFloat)

	// Extract change_id
	changeID, ok := args["change_id"].(string)
	if !ok || changeID == "" {
		return protocol.NewErrorResult("Missing required argument: change_id"), nil
	}

	// Load project from database
	dao := database.NewProjectDAO(h.db)
	project, err := dao.GetByChangeID(changeID)
	if err != nil {
		return protocol.NewErrorResult(fmt.Sprintf("Failed to load project: %v", err)), nil
	}

	// Find task by ID
	task := h.findTaskByID(project, taskID)
	if task == nil {
		return protocol.NewErrorResult(fmt.Sprintf("Task not found: %d", taskID)), nil
	}

	// Check if task is already completed
	if task.Execution.Status == "completed" {
		return protocol.NewErrorResult(fmt.Sprintf("Task already completed: %s", task.Name)), nil
	}

	// Check dependencies
	if err := h.checkDependencies(project, task); err != nil {
		return protocol.NewErrorResult(fmt.Sprintf("Dependency check failed: %v", err)), nil
	}

	// Build task prompt
	prompt, err := h.buildTaskPrompt(project, task)
	if err != nil {
		return protocol.NewErrorResult(fmt.Sprintf("Failed to build prompt: %v", err)), nil
	}

	// Update task status to in_progress
	now := time.Now()
	task.Execution.Status = "in_progress"
	task.Execution.StartedAt = &now

	// Call AI
	response, err := h.aiClient.CallClaude(prompt)
	if err != nil {
		task.Execution.Status = "failed"
		return protocol.NewErrorResult(fmt.Sprintf("AI call failed: %v", err)), nil
	}

	// Parse response
	result, err := h.parseTaskResponse(response)
	if err != nil {
		task.Execution.Status = "failed"
		return protocol.NewErrorResult(fmt.Sprintf("Failed to parse AI response: %v", err)), nil
	}

	// Save execution result
	if err := h.saveTaskExecution(changeID, taskID, task, result, prompt, response); err != nil {
		return protocol.NewErrorResult(fmt.Sprintf("Failed to save execution result: %v", err)), nil
	}

	// Update task status to completed
	completedAt := time.Now()
	task.Execution.Status = "completed"
	task.Execution.CompletedAt = &completedAt
	task.Execution.Result = result.Summary
	task.Status = "completed"

	// Save updated project
	if err := dao.Update(changeID, project); err != nil {
		return protocol.NewErrorResult(fmt.Sprintf("Failed to update project: %v", err)), nil
	}

	// Format success message
	message := fmt.Sprintf("✅ 任务执行成功！\n\n任务: %s\n文件: %s\n\n代码已生成并保存。",
		task.Name, result.FilePath)

	return protocol.NewSuccessResult(message), nil
}

// findTaskByID finds a task by ID in the project
func (h *TaskExecutionHandler) findTaskByID(project *workflow.WorkflowData, taskID int) *workflow.Task {
	for i := range project.Tasks.Items {
		if project.Tasks.Items[i].ID == fmt.Sprintf("task-%03d", taskID) {
			return &project.Tasks.Items[i]
		}
	}
	return nil
}

// checkDependencies checks if all dependencies are completed
func (h *TaskExecutionHandler) checkDependencies(project *workflow.WorkflowData, task *workflow.Task) error {
	for _, depID := range task.Dependencies {
		depTask := h.findTaskByIDString(project, depID)
		if depTask == nil {
			return fmt.Errorf("dependency task not found: %s", depID)
		}
		if depTask.Execution.Status != "completed" {
			return fmt.Errorf("dependency task not completed: %s (%s)", depTask.Name, depID)
		}
	}
	return nil
}

// findTaskByIDString finds a task by ID string
func (h *TaskExecutionHandler) findTaskByIDString(project *workflow.WorkflowData, taskID string) *workflow.Task {
	for i := range project.Tasks.Items {
		if project.Tasks.Items[i].ID == taskID {
			return &project.Tasks.Items[i]
		}
	}
	return nil
}

// buildTaskPrompt builds the task execution prompt
func (h *TaskExecutionHandler) buildTaskPrompt(project *workflow.WorkflowData, task *workflow.Task) (string, error) {
	var sb strings.Builder

	// Header
	sb.WriteString("# 任务执行请求\n\n")
	sb.WriteString(fmt.Sprintf("## 项目信息\n\n"))
	sb.WriteString(fmt.Sprintf("- **项目**: %s\n", project.Proposal.Summary))
	sb.WriteString(fmt.Sprintf("- **动机**: %s\n\n", project.Proposal.Motivation))

	// Task information
	sb.WriteString(fmt.Sprintf("## 任务信息\n\n"))
	sb.WriteString(fmt.Sprintf("- **任务 ID**: %s\n", task.ID))
	sb.WriteString(fmt.Sprintf("- **任务名称**: %s\n", task.Name))
	sb.WriteString(fmt.Sprintf("- **任务描述**: %s\n\n", task.Description))

	// Deliverables
	if len(task.Deliverables) > 0 {
		sb.WriteString("## 交付物要求\n\n")
		for i, d := range task.Deliverables {
			sb.WriteString(fmt.Sprintf("%d. **类型**: %s\n", i+1, d.Type))
			sb.WriteString(fmt.Sprintf("   - **路径**: %s\n", d.Path))
			sb.WriteString(fmt.Sprintf("   - **描述**: %s\n", d.Description))
			if len(d.AcceptanceCriteria) > 0 {
				sb.WriteString("   - **验收标准**:\n")
				for _, ac := range d.AcceptanceCriteria {
					sb.WriteString(fmt.Sprintf("     - %s\n", ac))
				}
			}
			sb.WriteString("\n")
		}
	}

	// Verification
	sb.WriteString("## 验证标准\n\n")
	sb.WriteString(fmt.Sprintf("- **验证类型**: %s\n", task.Verification.Type))
	if len(task.Verification.ScenarioRefs) > 0 {
		sb.WriteString("- **关联场景**:\n")
		for _, ref := range task.Verification.ScenarioRefs {
			scenario := h.findScenarioByID(project, ref)
			if scenario != nil {
				sb.WriteString(fmt.Sprintf("  - **%s**: %s\n", scenario.ID, scenario.Name))
				sb.WriteString(fmt.Sprintf("    - WHEN: %s\n", scenario.When))
				sb.WriteString(fmt.Sprintf("    - THEN: %s\n", scenario.Then))
			}
		}
	}
	if len(task.Verification.ManualCheck) > 0 {
		sb.WriteString("- **手动检查**:\n")
		for _, check := range task.Verification.ManualCheck {
			sb.WriteString(fmt.Sprintf("  - %s\n", check))
		}
	}
	sb.WriteString("\n")

	// Related requirements
	sb.WriteString("## 相关需求\n\n")
	for i, req := range project.Spec.Requirements {
		sb.WriteString(fmt.Sprintf("%d. **%s** (%s)\n", i+1, req.Name, req.ID))
		sb.WriteString(fmt.Sprintf("   - %s\n\n", req.Description))
	}

	// Instructions
	sb.WriteString("## 执行指令\n\n")
	sb.WriteString("请根据以上信息生成实现代码。返回格式如下：\n\n")
	sb.WriteString("```json\n")
	sb.WriteString("{\n")
	sb.WriteString("  \"code\": \"完整的代码实现\",\n")
	sb.WriteString("  \"file_path\": \"文件路径（例如：internal/service/user.go）\",\n")
	sb.WriteString("  \"summary\": \"实现摘要（简要说明实现了什么）\"\n")
	sb.WriteString("}\n")
	sb.WriteString("```\n")

	return sb.String(), nil
}

// findScenarioByID finds a scenario by ID
func (h *TaskExecutionHandler) findScenarioByID(project *workflow.WorkflowData, scenarioID string) *workflow.Scenario {
	for _, req := range project.Spec.Requirements {
		for i := range req.Scenarios {
			if req.Scenarios[i].ID == scenarioID {
				return &req.Scenarios[i]
			}
		}
	}
	return nil
}

// parseTaskResponse parses AI task execution response
func (h *TaskExecutionHandler) parseTaskResponse(response string) (*TaskExecutionResponse, error) {
	// Extract JSON from markdown code blocks
	jsonStart := strings.Index(response, "```json")
	jsonEnd := strings.LastIndex(response, "```")

	var jsonStr string
	if jsonStart != -1 && jsonEnd != -1 && jsonEnd > jsonStart {
		jsonStr = response[jsonStart+7 : jsonEnd]
		jsonStr = strings.TrimSpace(jsonStr)
	} else {
		jsonStr = response
	}

	// Parse JSON
	var result TaskExecutionResponse
	if err := json.Unmarshal([]byte(jsonStr), &result); err != nil {
		return nil, fmt.Errorf("failed to parse JSON: %w", err)
	}

	return &result, nil
}

// saveTaskExecution saves task execution result to database
func (h *TaskExecutionHandler) saveTaskExecution(changeID string, taskID int, task *workflow.Task, result *TaskExecutionResponse, prompt string, response string) error {
	// Begin transaction
	tx, err := h.db.Begin()
	if err != nil {
		return fmt.Errorf("failed to begin transaction: %w", err)
	}
	defer tx.Rollback()

	// Get project ID
	var projectID int
	err = tx.QueryRow("SELECT id FROM projects WHERE change_id = ?", changeID).Scan(&projectID)
	if err != nil {
		return fmt.Errorf("failed to get project ID: %w", err)
	}

	// Insert execution record
	_, err = tx.Exec(`
		INSERT INTO task_executions (project_id, task_id, task_name, prompt_used, ai_response, generated_code, file_path, status, created_at)
		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
		projectID, taskID, task.Name, prompt, response, result.Code, result.FilePath, "completed", time.Now())
	if err != nil {
		return fmt.Errorf("failed to insert execution record: %w", err)
	}

	// Commit transaction
	if err := tx.Commit(); err != nil {
		return fmt.Errorf("failed to commit transaction: %w", err)
	}

	return nil
}
